package com.zhijian.warehouse.manage.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.zhijian.warehouse.manage.dao.MenuMapper;
import com.zhijian.warehouse.manage.entity.po.Menu;
import com.zhijian.warehouse.manage.entity.po.User;
import com.zhijian.warehouse.manage.entity.vo.request.MenuSearchVo;
import com.zhijian.warehouse.manage.entity.vo.response.MenuByRoleVo;
import com.zhijian.warehouse.manage.entity.vo.response.MenuVo;
import com.zhijian.warehouse.manage.service.MenuService;
import com.zhijian.warehouse.manage.service.RoleMenuService;
import com.zhijian.warehouse.manage.service.UserRoleService;
import com.zhijian.warehouse.manage.service.UserService;
import com.zhijian.util.page.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统菜单信息业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-01-22 15:30:23
 */
@Slf4j
@Service
public class MenuServiceImpl implements MenuService {

    @Autowired
    private MenuMapper mapper;

    @Autowired
    private RoleMenuService roleMenuService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserRoleService userRoleService;

    @Override
    public Menu selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public MenuVo selectVoById(Long id) {
        return mapper.selectVoById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
        roleMenuService.deleteByMenuId(id);
    }

    @Override
    public Long insert(Menu menu) {
        Date now = new Date();
        menu.setCreateTime(now);
        menu.setUpdateTime(now);
        return mapper.insert(menu) > 0 ? menu.getId() : 0L;
    }

    @Override
    public boolean update(Menu menu) {
        Date now = new Date();
        menu.setUpdateTime(now);
        return mapper.updateByPrimaryKey(menu) != 0;
    }

    @Override
    public Integer count(MenuSearchVo menuSearchVo) {
        return mapper.count(menuSearchVo);
    }

    @Override
    public List<MenuVo> selectList(MenuSearchVo menuSearchVo) {
        return mapper.selectList(menuSearchVo);
    }

    @Override
    public Page<MenuVo> selectPage(MenuSearchVo menuSearchVo) {
        //先直接查总数
        int count = count(menuSearchVo);
        //分页
        Page<MenuVo> page = new Page<>(true, count, menuSearchVo.getPageNum(), menuSearchVo.getPageSize());
        menuSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<MenuVo> responseVos = this.selectList(menuSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public List<MenuVo> selectTreeList(List<MenuVo> all, Long pid) {
        return createTree(all, pid);
    }

    @Override
    public List<MenuVo> renderTreeList() {
        List<MenuVo> menuVos = this.selectList(new MenuSearchVo());
        return selectTreeList(menuVos, 0L);
    }

    @Override
    public List<MenuVo> renderTreeListBySearch(MenuSearchVo menuSearchVo) {
        //最后返回的是这个租户管理员的菜单权限
        List<MenuVo> menuVos = this.selectList(menuSearchVo);
        if (CollectionUtil.isEmpty(menuVos)) {
            return Collections.emptyList();
        }
        return selectTreeList(menuVos, menuVos.stream().map(MenuVo::getParentId).min(Long::compareTo).orElse(0L));
    }

    @Override
    public MenuByRoleVo selectMenuByRoleVoByRoleId(Long roleId) {
        List<MenuVo> menuVoList = this.renderTreeList();
        List<Long> checkIds = roleMenuService.selectMenuIdsByRoleId(roleId);
        return MenuByRoleVo.builder()
                .menuList(menuVoList)
                .checkIds(checkIds)
                .build();
    }

    @Override
    public List<MenuVo> renderTreeListByRoleId(Long roleId) {
        List<MenuVo> menuVos = this.selectListWithButtonsByRoleId(roleId);
        return selectTreeList(menuVos, 0L);
    }

    @Override
    public List<MenuVo> renderTreeListByUserId(Long userId) {
        List<MenuVo> menuVos = this.selectListWithButtonsByUserId(userId);
        return selectTreeList(menuVos, 0L);
    }

    @Override
    public List<MenuVo> selectListByRoleId(Long roleId) {
        return mapper.selectListByRoleId(roleId);
    }

    @Override
    public List<MenuVo> selectListByUserId(Long userId) {
        return mapper.selectListByUserId(userId);
    }

    @Override
    public List<MenuVo> selectListWithButtonsByRoleId(Long roleId) {
        List<MenuVo> menuVos = this.selectListByRoleId(roleId);
        return menuVos;
    }

    @Override
    public List<MenuVo> selectListWithButtonsByUserId(Long userId) {
        List<MenuVo> menuVos = this.selectListByUserId(userId);
//        return setButtons(menuVos);
        return menuVos;
    }

    /**
     * 生成树的方法
     */
    private List<MenuVo> createTree(List<MenuVo> list, Long pid) {
        if (list.isEmpty()) {
            return list;
        }
        try {
            //根节点
            List<MenuVo> menuVos = new ArrayList<>();
            for (MenuVo menuVo : list) {
                //父节点是0的，为根节点。
                if (Objects.equals(menuVo.getParentId(), pid)) {
                    menuVos.add(menuVo);
                }
            }
            //为根id设置子childList是递归调用的
            for (MenuVo menuVo : menuVos) {
                /* 获取根节点下的所有子节点 使用getChild方法*/
                List<MenuVo> childList = setChild(menuVo.getId(), list);
                childList = childList.stream().sorted(Comparator.comparing(MenuVo::getSort)).collect(Collectors.toList());
                //给根节点设置子节点
                menuVo.setChildren(childList);
            }
            // 输出构建好的菜单数据。
            return menuVos;
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }

    /**
     * 获取子菜单
     * 获取子节点
     *
     * @param id   父节点id
     * @param list 所有节点列表
     * @return 每个根节点下，所有子节点列表
     */
    private List<MenuVo> setChild(Long id, List<MenuVo> list) {
        //子节点
        List<MenuVo> childList = new ArrayList<>();
        for (MenuVo menuVo : list) {
            // 遍历所有节点，将所有子节点的父id与传过来的根节点的id比较
            //相等说明：为该根节点的子节点。
            if (menuVo.getParentId().equals(id)) {
                childList.add(menuVo);
            }
        }
        //递归
        for (MenuVo menuVo : childList) {
            menuVo.setChildren(setChild(menuVo.getId(), list));
        }
        //如果节点下没有子节点，返回一个空List（递归退出）
        if (childList.isEmpty()) {
            return new ArrayList<>();
        }
        return childList;
    }

}